Allow to configure various devise settings in .env

Dominik Sander 9 years ago
parent
commit
ee1ebea830

+ 33 - 3
.env.example

@@ -40,9 +40,9 @@ DATABASE_PASSWORD=""
40 40
 # Should Rails force all requests to use SSL?
41 41
 FORCE_SSL=false
42 42
 
43
-############################
44
-#     Allowing Signups     #
45
-############################
43
+################################################
44
+#     User authentication and registration     #
45
+################################################
46 46
 
47 47
 # This invitation code will be required for users to signup with your Huginn installation.
48 48
 # You can see its use in user.rb.  PLEASE CHANGE THIS!
@@ -51,6 +51,36 @@ INVITATION_CODE=try-huginn
51 51
 # If you don't want to require new users to have an invitation code in order to sign up, set this to true.
52 52
 SKIP_INVITATION_CODE=false
53 53
 
54
+# If you'd like to require new users to confirm their email address after sign up, set this to true.
55
+REQUIRE_CONFIRMED_EMAIL=false
56
+
57
+# If REQUIRE_CONFIRMED_EMAIL is true, set this to the duration in which a user needs to confirm their email address.
58
+ALLOW_UNCONFIRMED_ACCESS_FOR=2.days
59
+
60
+# Duration for which the above confirmation token is valid
61
+CONFIRM_WITHIN=3.days
62
+
63
+# Minimum password length
64
+MIN_PASSWORD_LENGTH=8
65
+
66
+# Duration for which the reset password token is valid
67
+RESET_PASSWORD_WITHIN=6.hours
68
+
69
+# Set to 'failed_attempts' to lock user accounts for the UNLOCK_AFTER period they fail MAX_FAILED_LOGIN_ATTEMPTS login attempts. Set to 'none' to allow unlimited failed login attempts.
70
+LOCK_STRATEGY=failed_attempts
71
+
72
+# After how many failed login attempts the account is locked when LOCK_STRATEGY is set to failed_attempts.
73
+MAX_FAILED_LOGIN_ATTEMPTS=10
74
+
75
+# Can be set to 'email', 'time', 'both' or 'none'. 'none' requires manual unlocking of your users!
76
+UNLOCK_STRATEGY=both
77
+
78
+# Duration after which the user is unlocked when UNLOCK_STRATEGY is 'both' or 'time' and LOCK_STRATEGY is 'failed_attempts'
79
+UNLOCK_AFTER=1.hour
80
+
81
+# Duration for which the user will be remembered without asking for credentials again.
82
+REMEMBER_FOR=4.weeks
83
+
54 84
 #############################
55 85
 #    Email Configuration    #
56 86
 #############################

+ 5 - 3
app/models/user.rb

@@ -1,8 +1,10 @@
1 1
 # Huginn is designed to be a multi-User system.  Users have many Agents (and Events created by those Agents).
2 2
 class User < ActiveRecord::Base
3
-  devise :database_authenticatable, :registerable,
4
-         :recoverable, :rememberable, :trackable, :validatable, :lockable,
5
-         :omniauthable
3
+  DEVISE_MODULES = [:database_authenticatable, :registerable,
4
+                    :recoverable, :rememberable, :trackable,
5
+                    :validatable, :lockable, :omniauthable,
6
+                    (ENV['REQUIRE_CONFIRMED_EMAIL'] == 'true' ? :confirmable : nil)].compact
7
+  devise *DEVISE_MODULES
6 8
 
7 9
   INVITATION_CODES = [ENV['INVITATION_CODE'] || 'try-huginn']
8 10
 

+ 9 - 9
config/initializers/devise.rb

@@ -103,7 +103,7 @@ Devise.setup do |config|
103 103
   # able to access the website for two days without confirming their account,
104 104
   # access will be blocked just in the third day. Default is 0.days, meaning
105 105
   # the user cannot access the website without confirming their account.
106
-  # config.allow_unconfirmed_access_for = 2.days
106
+  config.allow_unconfirmed_access_for = Utils.parse_duration(ENV['ALLOW_UNCONFIRMED_ACCESS_FOR']).presence || 2.days
107 107
 
108 108
   # A period that the user is allowed to confirm their account before their
109 109
   # token becomes invalid. For example, if set to 3.days, the user can confirm
@@ -111,7 +111,7 @@ Devise.setup do |config|
111 111
   # their account can't be confirmed with the token any more.
112 112
   # Default is nil, meaning there is no restriction on how long a user can take
113 113
   # before confirming their account.
114
-  # config.confirm_within = 3.days
114
+  config.confirm_within = Utils.parse_duration(ENV['CONFIRM_WITHIN']).presence || 3.days
115 115
 
116 116
   # If true, requires any email changes to be confirmed (exactly the same way as
117 117
   # initial account confirmation) to be applied. Requires additional unconfirmed_email
@@ -124,7 +124,7 @@ Devise.setup do |config|
124 124
 
125 125
   # ==> Configuration for :rememberable
126 126
   # The time the user will be remembered without asking for credentials again.
127
-  config.remember_for = 4.weeks
127
+  config.remember_for = Utils.parse_duration(ENV['REMEMBER_FOR']).presence || 4.weeks
128 128
 
129 129
   # Invalidates all the remember me tokens when the user signs out.
130 130
   config.expire_all_remember_me_on_sign_out = true
@@ -142,7 +142,7 @@ Devise.setup do |config|
142 142
 
143 143
   # ==> Configuration for :validatable
144 144
   # Range for password length.
145
-  config.password_length = 8..128
145
+  config.password_length = (Utils.if_present(ENV['MIN_PASSWORD_LENGTH'], :to_i) || 8)..128
146 146
 
147 147
   # Email regex used to validate email formats. It simply asserts that
148 148
   # one (and only one) @ exists in the given string. This is mainly
@@ -158,7 +158,7 @@ Devise.setup do |config|
158 158
   # Defines which strategy will be used to lock an account.
159 159
   # :failed_attempts = Locks an account after a number of failed attempts to sign in.
160 160
   # :none            = No lock strategy. You should handle locking by yourself.
161
-  config.lock_strategy = :failed_attempts
161
+  config.lock_strategy = Utils.if_present(ENV['LOCK_STRATEGY'], :to_sym) || :failed_attempts
162 162
 
163 163
   # Defines which key will be used when locking and unlocking an account
164 164
   config.unlock_keys = [ :email ]
@@ -168,14 +168,14 @@ Devise.setup do |config|
168 168
   # :time  = Re-enables login after a certain amount of time (see :unlock_in below)
169 169
   # :both  = Enables both strategies
170 170
   # :none  = No unlock strategy. You should handle unlocking by yourself.
171
-  config.unlock_strategy = :both
171
+  config.unlock_strategy = Utils.if_present(ENV['UNLOCK_STRATEGY'], :to_sym) || :both
172 172
 
173 173
   # Number of authentication tries before locking an account if lock_strategy
174 174
   # is failed attempts.
175
-  config.maximum_attempts = 10
175
+  config.maximum_attempts = Utils.if_present(ENV['MAX_FAILED_LOGIN_ATTEMPTS'], :to_i) || 10
176 176
 
177 177
   # Time interval to unlock the account if :time is enabled as unlock_strategy.
178
-  config.unlock_in = 1.hour
178
+  config.unlock_in = Utils.parse_duration(ENV['UNLOCK_AFTER']).presence || 1.hour
179 179
 
180 180
   # Warn on the last attempt before the account is locked.
181 181
   # config.last_attempt_warning = true
@@ -188,7 +188,7 @@ Devise.setup do |config|
188 188
   # Time interval you can reset your password with a reset password key.
189 189
   # Don't put a too small interval or your users won't have the time to
190 190
   # change their passwords.
191
-  config.reset_password_within = 6.hours
191
+  config.reset_password_within = Utils.parse_duration(ENV['RESET_PASSWORD_WITHIN']).presence || 6.hours
192 192
 
193 193
   # ==> Configuration for :encryptable
194 194
   # Allow you to use another encryption algorithm besides bcrypt (default). You can use

+ 17 - 0
db/migrate/20160301113717_add_confirmable_attributes_to_users.rb

@@ -0,0 +1,17 @@
1
+class AddConfirmableAttributesToUsers < ActiveRecord::Migration
2
+  def change
3
+    change_table(:users) do |t|
4
+      ## Confirmable
5
+      t.string   :confirmation_token
6
+      t.datetime :confirmed_at
7
+      t.datetime :confirmation_sent_at
8
+      t.string   :unconfirmed_email # Only if using reconfirmable
9
+    end
10
+
11
+    add_index :users, :confirmation_token,   unique: true
12
+
13
+    if ENV['REQUIRE_CONFIRMED_EMAIL'] != 'true' && ActiveRecord::Base.connection.column_exists?(:users, :confirmed_at)
14
+      User.update_all('confirmed_at = NOW()')
15
+    end
16
+  end
17
+end

+ 21 - 0
lib/utils.rb

@@ -130,4 +130,25 @@ module Utils
130 130
   def self.sort_tuples!(array, orders = [])
131 131
     TupleSorter.sort!(array, orders)
132 132
   end
133
+
134
+  def self.parse_duration(string)
135
+    return nil if string.blank?
136
+    case string.strip
137
+    when /\A(\d+)\.(\w+)\z/
138
+      $1.to_i.send($2.to_s)
139
+    when /\A(\d+)\z/
140
+      $1.to_i
141
+    else
142
+      STDERR.puts "WARNING: Invalid duration format: '#{string.strip}'"
143
+      nil
144
+    end
145
+  end
146
+
147
+  def self.if_present(string, method)
148
+    if string.present?
149
+      string.send(method)
150
+    else
151
+      nil
152
+    end
153
+  end
133 154
 end

+ 1 - 0
spec/env.test

@@ -11,3 +11,4 @@ WUNDERLIST_OAUTH_KEY=wunderoauthkey
11 11
 EVERNOTE_OAUTH_KEY=evernoteoauthkey
12 12
 EVERNOTE_OAUTH_SECRET=evernoteoauthsecret
13 13
 FAILED_JOBS_TO_KEEP=2
14
+REQUIRE_CONFIRMED_EMAIL=false

+ 29 - 0
spec/lib/utils_spec.rb

@@ -172,4 +172,33 @@ describe Utils do
172 172
       expect(tuples).to eq expected
173 173
     end
174 174
   end
175
+
176
+  context "#parse_duration" do
177
+    it "works with correct arguments" do
178
+      expect(Utils.parse_duration('2.days')).to eq(2.days)
179
+      expect(Utils.parse_duration('2.seconds')).to eq(2)
180
+      expect(Utils.parse_duration('2')).to eq(2)
181
+    end
182
+
183
+    it "returns nil when passed nil" do
184
+      expect(Utils.parse_duration(nil)).to be_nil
185
+    end
186
+
187
+    it "warns and returns nil when not parseable" do
188
+      mock(STDERR).puts("WARNING: Invalid duration format: 'bogus'")
189
+      expect(Utils.parse_duration('bogus')).to be_nil
190
+    end
191
+  end
192
+
193
+  context "#if_present" do
194
+    it "returns nil when passed nil" do
195
+      expect(Utils.if_present(nil, :to_i)).to be_nil
196
+    end
197
+
198
+    it "calls the specified method when the argument is present" do
199
+      argument = mock()
200
+      mock(argument).to_i { 1 }
201
+      expect(Utils.if_present(argument, :to_i)).to eq(1)
202
+    end
203
+  end
175 204
 end